package com.lovely3x.jobservice.executors.extensions.downloader2.utils;

import android.support.annotation.NonNull;
import android.text.TextUtils;

import com.lovely3x.common.utils.fileutils.StreamUtils;
import com.lovely3x.jobservice.executors.extensions.downloader2.executor.DownloadListener;
import com.lovely3x.jobservice.utils.Utils;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 下载工具,下载由这个工具实现
 * Created by lovely3x on 16-1-28.
 */
public class DownloadUtils {

    public static final String REQUEST_METHOD_POST = "POST";
    public static final String REQUEST_METHOD_GET = "GET";
    /**
     * 响应头:是否支持通过字节断点续传
     * 如果通过这个头获取的值不为空,则说明支持
     */
    public static final String HEADER_ALLOW_RANGES = "Accept-Ranges";
    /**
     * 请求的文件的内容长度
     * 如果无法明确服务器的资源的长度，该Header将不存在或 值为-1
     */
    public static final String HEADER_CONTENT_LENGTH = "Content-Length";

    /**
     * 指定下载范围的头
     */
    public static final String HEADER_RANGE_KEY = "RANGE";
    /**
     * 指定下载的范围，是一个格式化字符串
     * 使用时需要先格式化
     */
    public static final String HEADER_RANGE_VALUE = "bytes=%s-%s";

    /**
     * 内容类型
     */
    public static final String HEADER_CONTENT_TYPE = "Content-Type";

    /**
     * 内容的md5
     */
    public static final String HEADER_CONTENT_MD5 = "Content-MD5";

    /**
     * 内容的规定
     */
    public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";

    /**
     * 支持的请求方式
     */
    public static final String HEADER_ALLOW_REQUEST_METHOD = "Access-Control-Allow-Methods";

    /**
     * 下载的内存缓冲区大小
     */
    public static final int BUFFER_SIZE = 1024 * 16;

    private static final int READ_TIME_OUT = 30 * 1000;
    private static final int CONNECT_TIME_OUT = 20 * 1000;

    /**
     * 下载一个块
     *
     * @param url            需要下载的地址
     * @param method         请求的方式
     * @param alreadyReadLen 已经读取的长度
     * @param start          起始位置
     * @param end            结束位置
     * @param taskWhat       任务的标识
     * @param partSequence   块标识
     * @param listener       下载监听器
     */
    public static void downloadPart(@NonNull String url, String method,
                                    long alreadyReadLen,
                                    long start, long end, long taskWhat, int partSequence, @NonNull DownloadListener listener) {

        long alreadyRead = alreadyReadLen;
        InputStream inputStream = null;
        try {
            URL u = new URL(url);
            HttpURLConnection httpConnection = (HttpURLConnection) u.openConnection();
            httpConnection.setReadTimeout(READ_TIME_OUT);
            httpConnection.setConnectTimeout(CONNECT_TIME_OUT);

            if (start != -1 && end != -1) {
                httpConnection.setRequestProperty(HEADER_RANGE_KEY, String.format(HEADER_RANGE_VALUE, start + alreadyReadLen, end));
            }

            httpConnection.setRequestMethod(method);
            if (REQUEST_METHOD_POST.equals(method)) {
                httpConnection.setDoOutput(true);
                httpConnection.setDoInput(true);
            }

            httpConnection.connect();
            int retCode = httpConnection.getResponseCode();
            if (retCode >= 200 && retCode <= 300) {
                inputStream = httpConnection.getInputStream();
                byte[] buffer = new byte[BUFFER_SIZE];
                int len = -1;
                while ((len = inputStream.read(buffer)) != -1) {
                    if (len != 0) {
                        alreadyRead += len;
                        listener.onDoing(start, end, alreadyRead, taskWhat, partSequence, buffer, len);
                        if (listener.cancel()) {
                            listener.onCancel(start, end, alreadyRead, taskWhat, partSequence);
                            return;
                        }
                    }
                }
                listener.onSuccessful(start, end, alreadyRead, taskWhat, partSequence);
            } else {
                listener.onFailure(new Exception(String.format("Http Status Code Exception %d ", retCode)), start, end, 0, taskWhat, partSequence);
            }
        } catch (Exception e) {
            listener.onFailure(e, start, end, alreadyRead, taskWhat, partSequence);
        } finally {
            StreamUtils.close(inputStream);
        }
    }

    /**
     * 获取指定的地址的文件的长度,如果获取的目标长度为-1则表示不可以获取内容长度
     *
     * @param url 需要获取的的内容长度的地址
     */
    public static long getContentLength(String url) {
        long numericContentLength = -1;
        HttpURLConnection httpConnection = null;
        try {
            URL u = new URL(url);
            httpConnection = (HttpURLConnection) u.openConnection();
            httpConnection.setReadTimeout(READ_TIME_OUT);
            httpConnection.setConnectTimeout(CONNECT_TIME_OUT);
            String contentLength = httpConnection.getHeaderField(HEADER_CONTENT_LENGTH);
            numericContentLength = Long.parseLong(contentLength);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (httpConnection != null) httpConnection.disconnect();
        }
        return numericContentLength;
    }

    /**
     * 获取指定的地址的文件的信息,如果获取失败返回null
     *
     * @param url 需要获取的的文件信息的地址
     */
    public static ResponseInfo getFileInfo(String url) {
        HttpURLConnection httpConnection = null;
        try {
            URL u = new URL(url);
            httpConnection = (HttpURLConnection) u.openConnection();
            httpConnection.setReadTimeout(READ_TIME_OUT);
            httpConnection.setConnectTimeout(CONNECT_TIME_OUT);


            ResponseInfo ri = new ResponseInfo();
            ri.contentType = httpConnection.getHeaderField(HEADER_CONTENT_TYPE);
            ri.contentMD5 = httpConnection.getHeaderField(HEADER_CONTENT_MD5);
            ri.contentDisposition = httpConnection.getHeaderField(HEADER_CONTENT_DISPOSITION);
            String contentLength = httpConnection.getHeaderField(HEADER_CONTENT_LENGTH);
            if (Utils.isDigit(contentLength)) {
                ri.contentLength = Long.parseLong(contentLength);
            }
            String allowRanges = httpConnection.getHeaderField(HEADER_ALLOW_RANGES);
            if (!TextUtils.isEmpty(allowRanges)) ri.acceptRanges = allowRanges.split(",");
            String allowMethods = httpConnection.getHeaderField(HEADER_ALLOW_REQUEST_METHOD);
            if (!TextUtils.isEmpty(allowMethods)) ri.allowRequestMethod = allowMethods.split(",");
            return ri;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (httpConnection != null) httpConnection.disconnect();
        }
        return null;
    }

    /**
     * http文件信息
     */
    public static class ResponseInfo {
        //Content-Length
        //102934
        public long contentLength;
        //Content-Type
        //archive android package
        public String contentType;
        //Content-MD5
        public String contentMD5;
        //Content-Disposition
        public String contentDisposition;
        //Access-Control-Allow-Methods
        //HEAD, GET, OPTIONS, PUT, POST, DELETE
        public String[] allowRequestMethod;
        //Accept-Ranges
        //bytes,chars
        public String[] acceptRanges;

    }

}
